﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Windows.Data.Xml.Dom;
using Windows.Web.Syndication;

// The data model defined by this file serves as a representative example of a strongly-typed
// model that supports notification when members are added, removed, or modified.  The property
// names chosen coincide with data bindings in the standard item templates.
//
// Applications may use this model as a starting point and build on it, or discard it entirely and
// replace it with something appropriate to their needs.

namespace Enterprise_Store.Data
{

    /// <summary>
    /// Creates a collection of groups and items with hard-coded content.
    /// 
    /// SampleDataSource initializes with placeholder data rather than live production
    /// data so that sample data is provided at both design-time and run-time.
    /// </summary>
    public sealed class FeedDataSource
    {
        private static FeedDataSource _sampleDataSource = new FeedDataSource();

        private ObservableCollection<SampleDataGroup> _allGroups = new ObservableCollection<SampleDataGroup>();

        public ObservableCollection<SampleDataGroup> AllGroups
        {
            get { return this._allGroups; }
        }

        public static IEnumerable<SampleDataGroup> GetGroups(int numberToDisplay)
        {
            _sampleDataSource.loadData(numberToDisplay);
            return _sampleDataSource.AllGroups;
        }

        public static SampleDataGroup GetGroup(string uniqueId)
        {
            // Simple linear search is acceptable for small data sets
            var matches = _sampleDataSource.AllGroups.Where((group) => group.UniqueId.Equals(uniqueId));
            if (matches.Count() == 1) return matches.First();
            return null;
        }

        public static SampleDataItem GetItem(string uniqueId)
        {
            // Simple linear search is acceptable for small data sets
            var matches = _sampleDataSource.AllGroups.SelectMany(group => group.Items).Where((item) => item.UniqueId.Equals(uniqueId));
            if (matches.Count() == 1) return matches.First();
            return null;
        }

        public FeedDataSource()
        {
            
        }

        private async void loadData(int numberToDisplay)
        {

            XmlNodeList feeds = null;
            SampleDataGroup group;
            int cptFeeds = 0;

            if (SampleDataSource.file != null)
            {
                try
                {
                    SampleDataSource.file = await Windows.Storage.ApplicationData.Current.LocalFolder.GetFileAsync(App.ConfigurationFile);
                }
                catch (FileNotFoundException)
                {

                }

                //If there is no configuration file on the default location, read a demo one on the application package.
                // this is mostly used for a demo app in the Windows Store
                if (SampleDataSource.file == null)
                {
                    try
                    {
                        SampleDataSource.file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(@"Assets\StoreStructure.xml");
                    }
                    catch (FileNotFoundException)
                    {

                    }
                }
            }

            if (SampleDataSource.file != null)
            {
                XmlDocument doc = null;
                try
                {
                    doc = await XmlDocument.LoadFromFileAsync(SampleDataSource.file);

                    if (doc != null)
                    {
                        feeds = doc.SelectNodes("//xml/feed");
                        cptFeeds = feeds.Count;
                    }

                }
                catch (Exception)
                {

                }

                if (feeds != null)
                {
                    String feedName = "", feedURI = "";
                    bool add = true;
                    for (int cptTst1 = 0; cptTst1 < cptFeeds; cptTst1++)
                    {
                        // Create the group that will contains the application
                        if (feeds.ElementAt(cptTst1).Attributes.GetNamedItem("name") != null)
                            feedName = feeds.ElementAt(cptTst1).Attributes.GetNamedItem("name").InnerText;
                        else
                            feedName = "Feed " + cptTst1;

                        if (feeds.ElementAt(cptTst1).Attributes.GetNamedItem("uri") != null)
                            feedURI = feeds.ElementAt(cptTst1).Attributes.GetNamedItem("uri").InnerText.Replace("??", "&");
                        else
                            feedURI = "";

                        group = new SampleDataGroup(feedName, feedName, "", "", "");
                        
                        await loadFeed(feedName, feedURI, group, numberToDisplay);
                        
                        foreach (SampleDataGroup g in this.AllGroups)
                        {
                            if (g.Title == feedName) add = false;
                        }
                        if(add)
                            this.AllGroups.Add(group);
                    }
                }
            }
        }


        private async Task loadFeed(String feedName, String feedURI, SampleDataGroup group, int numberToDisplay)
        {

            // By default 'FeedUri' is disabled and URI validation is not required. When enabling the text box
            // validating the URI is required since it was received from an untrusted source (user input).
            // The URI is validated by calling Uri.TryCreate() that will return 'false' for strings that are not valid URIs.
            // Note that when enabling the text box users may provide URIs to machines on the intrAnet that require
            // the "Home or Work Networking" capability.
            Uri uri;

            if (!Uri.TryCreate(feedURI.Trim(), UriKind.Absolute, out uri))
            {
                //rootPage.NotifyUser("Error: Invalid URI.", NotifyType.ErrorMessage);
                return;
            }

            SyndicationClient client = new SyndicationClient();
            client.BypassCacheOnRetrieve = true;

            // Although most HTTP servers do not require User-Agent header, others will reject the request or return
            // a different response if this header is missing. Use SetRequestHeader() to add custom headers.
            client.SetRequestHeader("User-Agent", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");

            //rootPage.NotifyUser("Downloading feed...", NotifyType.StatusMessage);
            //outputField.Text = "Downloading feed: " + uri.ToString() + "\r\n";

            try
            {
                SyndicationFeed currentFeed = await client.RetrieveFeedAsync(uri);
                //rootPage.NotifyUser("Feed download complete.", NotifyType.StatusMessage);

                //DisplayFeed();
                for (int cpt = 0; cpt < numberToDisplay; cpt++)
                {
                    SyndicationItem item = currentFeed.Items[cpt];

                    // Display the main link.
                    string link = string.Empty;
                    if (item.Links.Count > 0)
                    {
                        link = item.Links[0].Uri.AbsoluteUri;
                    }

                    // Display the body as HTML.
                    string content = "(no content)";
                    if (item.Content != null)
                    {
                        content = item.Content.Text;
                    }
                    else if (item.Summary != null)
                    {
                        content = item.Summary.Text;
                    }

                    group.Items.Add(new SampleDataItem(item.Title != null ? item.Title.Text : "item-" + cpt,
                        item.Title != null ? item.Title.Text : "(no title)",
                        System.Text.RegularExpressions.Regex.Replace(content, @"</?[^>]*>", ""),
                        "",
                        link,
                        "",
                        group));

                    // Display item extensions.
                    //extensionsListBox.ItemsSource = item.ElementExtensions;
                }
            }
            catch (Exception ex)
            {
                SyndicationErrorStatus status = SyndicationError.GetStatus(ex.HResult);
                /***
                 * if (status == SyndicationErrorStatus.InvalidXml)
                {
                    outputField.Text += "An invalid XML exception was thrown. " +
                        "Please make sure to use a URI that points to a RSS or Atom feed.";
                }

                if (status == SyndicationErrorStatus.Unknown)
                {
                    WebErrorStatus webError = WebError.GetStatus(ex.HResult);

                    if (webError == WebErrorStatus.Unknown)
                    {
                        // Neither a syndication nor a web error. Rethrow.
                        throw;
                    }
                }

                rootPage.NotifyUser(ex.Message, NotifyType.ErrorMessage);
                 */
            }
        }

        internal async static Task<int> nbFeeds()
        {
            XmlNodeList feeds = null;
            int cptFeeds = 0;
            int cptFeedsValid = 0;

            if (SampleDataSource.file != null)
            {
                try
                {
                    SampleDataSource.file = await Windows.Storage.ApplicationData.Current.LocalFolder.GetFileAsync(App.ConfigurationFile);
                }
                catch (FileNotFoundException)
                {

                }

                //If there is no configuration file on the default location, read a demo one on the application package.
                // this is mostly used for a demo app in the Windows Store
                if (SampleDataSource.file == null)
                {
                    try
                    {
                        SampleDataSource.file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(@"Assets\StoreStructure.xml");
                    }
                    catch (FileNotFoundException)
                    {

                    }
                }
            }

            if (SampleDataSource.file != null)
            {
                XmlDocument doc = null;
                try
                {
                    doc = await XmlDocument.LoadFromFileAsync(SampleDataSource.file);

                    if (doc != null)
                    {
                        feeds = doc.SelectNodes("//xml/feed");
                        cptFeeds = feeds.Count;
                        
                        for (int cpt = 0; cpt < cptFeeds; cpt++)
                        {
                            if (Uri.IsWellFormedUriString(feeds.ElementAt(cpt).Attributes.GetNamedItem("uri").InnerText, UriKind.Absolute))
                                cptFeedsValid++;
                        }
                    }

                }
                catch (Exception)
                {

                }
            }
            return cptFeedsValid;
        }

    }
}
